home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 1.0 beta / flock-1.0RC3.en-US.win32.exe / flock / components / flockProfiler.js < prev    next >
Text File  |  2007-10-18  |  13KB  |  401 lines

  1. // vim: ts=2 sw=2 expandtab cindent
  2. //
  3. // BEGIN FLOCK GPL
  4. // 
  5. // Copyright Flock Inc. 2005-2007
  6. // http://flock.com
  7. // 
  8. // This file may be used under the terms of of the
  9. // GNU General Public License Version 2 or later (the "GPL"),
  10. // http://www.gnu.org/licenses/gpl.html
  11. // 
  12. // Software distributed under the License is distributed on an "AS IS" basis,
  13. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14. // for the specific language governing rights and limitations under the
  15. // License.
  16. // 
  17. // END FLOCK GPL
  18. //
  19.  
  20. const Cc = Components.classes;
  21. const Ci = Components.interfaces;
  22. const Cr = Components.results;
  23.  
  24. const CLASS_ID = Components.ID("{2fd8e108-f21b-11db-8314-0800200c9a66}");
  25. const CONTRACT_ID = "@flock.com/profiler;1";
  26. const CATEGORY_COMPONENT_NAME = "Flock Profiler Component";
  27.  
  28. const GRAPH_HOST = "dippy.hq.flock.com";
  29. const CREATEGRAPH_URL = "http://%host%/ffgraphs.xml";
  30. const OBSERVATION_URL = "http://%host%/ffgraphs/%graphname%/ffmeasurements.xml";
  31.  
  32. const PREF_PROFILER = "flock.profiler.enabled";
  33. const PREF_REPORTING = "flock.profiler.reporting.enabled";
  34.  
  35. const EVENT_FLOCKDATAREADY = "flock-data-ready";
  36. const EVENT_XPCOMSHUTDOWN = "xpcom-shutdown";
  37.  
  38. var gGraphNames = [];
  39.  
  40. var gCompTK;
  41. function getCompTK() {
  42.   if (!gCompTK) {
  43.     gCompTK = Cc["@flock.com/singleton;1"]
  44.                 .getService(Ci.flockISingleton)
  45.                 .getSingleton("chrome://browser/content/flock/services/common/load-compTK.js")
  46.                 .wrappedJSObject;
  47.   }
  48.   return gCompTK;
  49. }
  50.  
  51.  
  52. // ===============================================
  53. // ========== BEGIN flockProfiler class ==========
  54. // ===============================================
  55.  
  56. function flockProfiler()
  57. {
  58.   // Use a logger to spit out data to the console
  59.   this._logger = Cc["@flock.com/logger;1"].createInstance(Ci.flockILogger);
  60.   this._logger.init("profiler");
  61.  
  62.   // The System Info service will be used to get some performance data
  63.   this._sysinfo = Cc["@flock.com/sysinfo;1"].getService(Ci.flockISystemInfo);
  64.   var buildInfo = this._sysinfo.getBuildInfo().split(",");
  65.   this._platform = buildInfo[0];
  66.   this._firstRun = (buildInfo[1] == "1");
  67.   this._startTime = (new Date()).getTime();
  68.   //this._startTime = this._sysinfo.getStartTime();
  69.   var sysinfoTime = this._sysinfo.getStartTime();
  70.   this._logger.debug("start time reported by sysinfo:"+sysinfoTime);
  71.   this._logger.info("construction time: "+this._startTime);
  72.  
  73.   // Register to observe application initialization and shutdown events
  74.   this._obs = Cc["@mozilla.org/observer-service;1"]
  75.     .getService(Ci.nsIObserverService);
  76.   this.mInitialized = false;
  77.   this._obs.addObserver(this, EVENT_FLOCKDATAREADY, false); // calls _init()
  78.   this._obs.addObserver(this, EVENT_XPCOMSHUTDOWN, false);
  79.  
  80.   // This will be used to store open profiling events
  81.   this._eventQueue = [];
  82.  
  83.   // These will be overridden in _init()
  84.   this._profilingEnabled = false;
  85.   this._reportingEnabled = false;
  86.  
  87.   // Use Component Toolkit to implement basic interfaces
  88.   this._ctk = {
  89.     interfaces: [
  90.       "nsISupports",
  91.       "nsIClassInfo",
  92.       "nsISupportsCString",
  93.       "nsIObserver",
  94.       "flockIProfiler"
  95.     ],
  96.     shortName: "profiler",
  97.     fullName: "Flock Profiler",
  98.     CID: CLASS_ID,
  99.     contractID: CONTRACT_ID
  100.   };
  101. }
  102.  
  103.  
  104. // BEGIN nsIObserver
  105. flockProfiler.prototype.observe =
  106. function flockProfiler_observe(aSubject, aTopic, aData)
  107. {
  108.   switch (aTopic) {
  109.  
  110.     case EVENT_FLOCKDATAREADY:
  111.     {
  112.       this._obs.removeObserver(this, EVENT_FLOCKDATAREADY);
  113.       this._init();
  114.     }; break;
  115.  
  116.     case EVENT_XPCOMSHUTDOWN:
  117.     {
  118.       this._obs.removeObserver(this, EVENT_XPCOMSHUTDOWN);
  119.  
  120.       // Don't accept any more profiling calls or reporting after shutdown
  121.       this._profilingEnabled = false;
  122.       this._reportingEnabled = false;
  123.  
  124.       // Flush the event queue
  125.       this._eventQueue = [];
  126.     }; break;
  127.  
  128.   }
  129. }
  130. // END nsIObserver
  131.  
  132.  
  133. // BEGIN flockIProfiler
  134. flockProfiler.prototype.profile =
  135. function flockProfiler_profile(aEventName, aMessage)
  136. {
  137.   this._init();
  138.   if (!this._profilingEnabled) return;
  139.   var inst = this;
  140.   var pEvent = {
  141.     seq: inst._getProfileSeq(),
  142.     name: aEventName,
  143.     clock: inst._getTimeSinceStart(),
  144.     msg: aMessage,
  145.     ready: true
  146.   };
  147.   pEvent.cpu = this._sysinfo.getCPU();
  148.   pEvent.mem = this._sysinfo.getMem();
  149.   this._eventQueue.push(pEvent);
  150.   this._logEvent(pEvent);
  151. }
  152.  
  153. flockProfiler.prototype.profileEventStart =
  154. function flockProfiler_profileEventStart(aEventName)
  155. {
  156.   this._init();
  157.   if (!this._profilingEnabled) return 0;
  158.   var inst = this;
  159.   var pEvent = {
  160.     seq: inst._getProfileSeq(),
  161.     name: aEventName,
  162.     clock: inst._getTimeSinceStart()
  163.   };
  164.   //pEvent.cpu = this._sysinfo.getCPU();
  165.   //pEvent.mem = this._sysinfo.getMem();
  166.   this._eventQueue.push(pEvent);
  167.   //this._logEvent(pEvent);
  168.   return pEvent.seq;
  169. }
  170.  
  171. flockProfiler.prototype.profileEventEnd =
  172. function flockProfiler_profileEventEnd(aEventID, aMessage)
  173. {
  174.   if (!this._profilingEnabled) return;
  175.   // Find the event start
  176.   var pEvent = null;
  177.   for (var i = this._eventQueue.length - 1; i >= 0; i--) {
  178.     if (this._eventQueue[i].seq == aEventID) {
  179.       pEvent = this._eventQueue[i];
  180.       break;
  181.     }
  182.   }
  183.   if (!pEvent) return;
  184.   pEvent.duration = this._getTimeSinceStart() - pEvent.clock;
  185.   pEvent.cpu = this._sysinfo.getCPU();
  186.   pEvent.mem = this._sysinfo.getMem();
  187.   pEvent.msg = aMessage;
  188.   pEvent.ready = true;
  189.   this._logEvent(pEvent);
  190. }
  191. // END flockIProfiler
  192.  
  193.  
  194. flockProfiler.prototype._init =
  195. function flockProfiler__init()
  196. {
  197.   if (this.mInitialized) return;
  198.  
  199.   // Check prefs to see if we should be enabled
  200.   var prefSvc = Cc["@mozilla.org/preferences-service;1"]
  201.     .getService(Ci.nsIPrefBranch);
  202.   this._profilingEnabled = ( prefSvc.getPrefType(PREF_PROFILER) &&
  203.                              prefSvc.getBoolPref(PREF_PROFILER) );
  204.   this._reportingEnabled = ( prefSvc.getPrefType(PREF_REPORTING) &&
  205.                              prefSvc.getBoolPref(PREF_REPORTING) );
  206.   
  207.   // Kick off a timer for processing the event queue
  208.   if (this._profilingEnabled && this._reportingEnabled) {
  209.     var inst = this;
  210.     var timerCB = { notify: function (aTimer) { inst._processEventQueue(); } };
  211.     var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  212.     timer.initWithCallback(timerCB, 10 * 1000, Ci.nsITimer.TYPE_ONE_SHOT);
  213.   }
  214.  
  215.   this.mInitialized = true;
  216. }
  217.  
  218. flockProfiler.prototype._getProfileSeq =
  219. function flockProfiler__getProfileSeq()
  220. {
  221.   return this._eventQueue.length + 1;
  222. }
  223.  
  224. flockProfiler.prototype._logEvent =
  225. function flockProfiler__logEvent(aEvent)
  226. {
  227.   var msg = "";
  228.   var props = ["seq","name","clock","duration","cpu","mem","msg"];
  229.   for (var p in props) {
  230.     if (aEvent[props[p]] == undefined) continue;
  231.     if (msg.length > 0) msg += " ";
  232.     msg += props[p]+":"+aEvent[props[p]];
  233.   }
  234.   this._logger.info(msg);
  235. }
  236.  
  237. flockProfiler.prototype._getTimeSinceStart =
  238. function flockProfiler__getTimeSinceStart()
  239. {
  240.   var timeNow = (new Date()).getTime();
  241.   var timeElapsed = timeNow - this._startTime;
  242.   //dump("CDC profiling: timeNow: "+timeNow+" timeElapsed:"+timeElapsed+"\n");
  243.   return timeElapsed;
  244. }
  245.  
  246. flockProfiler.prototype._ensureGraphExists =
  247. function flockProfiler__ensureGraphExists(aGraphName, aUnits, aListener)
  248. {
  249.   if (!this._reportingEnabled) return;
  250.   if (gGraphNames[aGraphName] != undefined) {
  251.     aListener.onSuccess();
  252.   } else {
  253.     var inst = this;
  254.     var hr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
  255.                .createInstance(Ci.nsIXMLHttpRequest);
  256.     hr.onreadystatechange = function (aEvent) {
  257.       if (hr.readyState == 4) {
  258.         gGraphNames[aGraphName] = true;
  259.         //inst._logger.info("created graph: "+aGraphName);
  260.         //inst._logger.info("graph creation status: "+hr.status+" "+hr.statusText);
  261.         //inst._logger.info("response text:"+hr.responseText);
  262.         aListener.onSuccess();
  263.       }
  264.     };
  265.     var graphURL = CREATEGRAPH_URL.replace("%host%", GRAPH_HOST)
  266.     hr.open("POST", graphURL);
  267.     var postBody = "ffgraph[name]="+aGraphName
  268.                  + "&ffgraph[units]="+aUnits
  269.                  + "&ffgraph[password]=flock";
  270.     //inst._logger.info("POST to URL: "+graphURL);
  271.     //inst._logger.info("POST body: "+postBody);
  272.     hr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  273.     hr.send(postBody);
  274.   }
  275. }
  276.  
  277. flockProfiler.prototype._submitObservations =
  278. function flockProfiler__submitObservations(aProfilingEvent)
  279. {
  280.   if (!this._reportingEnabled) return;
  281.   var obsTypes = ["clock","duration","cpu","mem"];
  282.   var obsUnits = ["ms","ms","%","Mb"];
  283.   for (var i in obsTypes) {
  284.     var obsType = obsTypes[i];
  285.     if (aProfilingEvent[obsType] != undefined) {
  286.       switch (obsType) {
  287.         case "cpu": case "mem":
  288.           // Don't bother recording null observations
  289.           if (aProfilingEvent[obsType] == 0) { continue; }
  290.       }
  291.       var graphName = aProfilingEvent.name+"%20"+obsType+"%20"+this._platform;
  292.       if (this._firstRun) graphName += "%20FR";
  293.       var inst = this;
  294.       var graphCreationListener = {
  295.         graphName: graphName,
  296.         obsType: obsType,
  297.         onSuccess: function () {
  298.           if (!inst._reportingEnabled) return;
  299.           var hr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
  300.                      .createInstance(Ci.nsIXMLHttpRequest);
  301.           hr.onreadystatechange = function (aHTTPEvent) {
  302.             if (hr.readyState == 4) {
  303.               aProfilingEvent.sent = true;
  304.             }
  305.           };
  306.           var obsURL = OBSERVATION_URL.replace("%host%", GRAPH_HOST)
  307.                                       .replace("%graphname%", this.graphName);
  308.           hr.open("POST", obsURL);
  309.           var postBody = "ffmeasurement[data]="+aProfilingEvent[this.obsType]
  310.                        + "&ffmeasurement[notes]="+escape(aProfilingEvent.msg);
  311.           //inst._logger.info("POST to URL: "+obsURL);
  312.           //inst._logger.info("POST body: "+postBody);
  313.           hr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  314.           hr.setRequestHeader("Authorization", "Basic OmZsb2Nr"); // Base64(":flock")
  315.           hr.send(postBody);
  316.         }
  317.       };
  318.       this._ensureGraphExists(graphName, obsUnits[i], graphCreationListener);
  319.     }
  320.   }
  321. }
  322.  
  323. flockProfiler.prototype._processEventQueue =
  324. function flockProfiler__processEventQueue()
  325. {
  326.   if (!this._reportingEnabled) return;
  327.   //this._logger.info("_processEventQueue()");
  328.   while (this._eventQueue.length && this._eventQueue[0].sent) {
  329.     this._eventQueue.shift();
  330.   }
  331.   var profilingEvent = null;
  332.   var pos = 0;
  333.   while (!profilingEvent && (pos < this._eventQueue.length)) {
  334.     if (this._eventQueue[pos].ready) {
  335.       profilingEvent = this._eventQueue[pos];
  336.       break;
  337.     }
  338.     pos++;
  339.   }
  340.   if (profilingEvent) {
  341.     this._submitObservations(profilingEvent);
  342.   }
  343.   var inst = this;
  344.   var timerCB = { notify: function (aTimer) { inst._processEventQueue(); } };
  345.   var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  346.   timer.initWithCallback(timerCB, 5 * 1000, Ci.nsITimer.TYPE_ONE_SHOT);
  347. }
  348. // ========== END flockProfiler class ==========
  349.  
  350.  
  351. // ================================================
  352. // ========== BEGIN XPCOM Module support ==========
  353. // ================================================
  354.  
  355. function createModule(aParams) {
  356.   return {
  357.     registerSelf: function (aCompMgr, aFileSpec, aLocation, aType) {
  358.       aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
  359.       aCompMgr.registerFactoryLocation( aParams.CID, aParams.componentName,
  360.                                         aParams.contractID, aFileSpec,
  361.                                         aLocation, aType );
  362.       var catMgr = Cc["@mozilla.org/categorymanager;1"]
  363.         .getService(Ci.nsICategoryManager);
  364.       catMgr.addCategoryEntry( "flock-startup", aParams.componentName,
  365.                                "service,"+aParams.contractID, true, true );
  366.       if (!aParams.categories) { aParams.categories = []; }
  367.       for (var i = 0; i < aParams.categories.length; i++) {
  368.         var cat = aParams.categories[i];
  369.         catMgr.addCategoryEntry( cat.category, cat.entry,
  370.                                  cat.value, true, true );
  371.       }
  372.     },
  373.     getClassObject: function (aCompMgr, aCID, aIID) {
  374.       if (!aCID.equals(aParams.CID)) { throw Cr.NS_ERROR_NO_INTERFACE; }
  375.       if (!aIID.equals(Ci.nsIFactory)) { throw Cr.NS_ERROR_NOT_IMPLEMENTED; }
  376.       return { // Factory
  377.         createInstance: function (aOuter, aIID) {
  378.           if (aOuter != null) { throw Cr.NS_ERROR_NO_AGGREGATION; }
  379.           var comp = new aParams.componentClass();
  380.           if (aParams.implementationFunc) { aParams.implementationFunc(comp); }
  381.           return comp.QueryInterface(aIID);
  382.         }
  383.       };
  384.     },
  385.     canUnload: function (aCompMgr) { return true; }
  386.   };
  387. }
  388.  
  389. // NS Module entrypoint
  390. function NSGetModule(aCompMgr, aFileSpec) {
  391.   return createModule({
  392.     componentClass: flockProfiler,
  393.     CID: CLASS_ID,
  394.     contractID: CONTRACT_ID,
  395.     componentName: CATEGORY_COMPONENT_NAME,
  396.     implementationFunc: function (aComp) { getCompTK().addAllInterfaces(aComp); }
  397.   });
  398. }
  399.  
  400. // ========== END XPCOM Module support ==========
  401.